/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package client;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.ArrayList;
import datagram.Datagram;
/**
 *
 * @author rmb
 */
public class Send extends Thread{
    
    private DatagramSocket socket;
    private InetAddress address;
    private boolean pause;
    
    private ArrayList<DatagramPacket> toSend;
    private long sent_packs;
    
    private int currentWindow;
    private int window;

    public Send(DatagramSocket socket, InetAddress address) {
        this.socket = socket;
        this.address = address;        
        sent_packs = 0;
        pause = false;
        currentWindow = 0;
    }

    public void setFile(String fileDatapath) throws IOException{
        toSend = new ArrayList<DatagramPacket>();

        generatePackets(fileDatapath);
        
        sent_packs = -1;
    }
            
    public InetAddress getAddress() {
        return address;
    }

    public int getCurrentWindow() {
        return currentWindow;
    }

    public boolean isPause() {
        return pause;
    }

    public long getSent_packs() {
        return sent_packs;
    }

    public DatagramSocket getSocket() {
        return socket;
    }

    public ArrayList<DatagramPacket> getToSend() {
        ArrayList<DatagramPacket> tmp = new ArrayList<DatagramPacket>();
        
        try {
            for (DatagramPacket d : toSend) {
                tmp.add(d);
            }
         }
        catch(NullPointerException e) {}
            
        return tmp;
    }

    public int getWindow() {
        return window;
    }

    public void setAddress(InetAddress address) {
        this.address = address;
    }

    public void setCurrentWindow(int currentWindow) {
        this.currentWindow = currentWindow;
    }

    public void setPause(boolean pause) {
        this.pause = pause;
    }

    public void setSent_packs(long sent_packs) {
        this.sent_packs = sent_packs;
    }

    public void setSocket(DatagramSocket socket) {
        this.socket = socket;
    }

    public void setToSend(ArrayList<DatagramPacket> toSend) {
        this.toSend = toSend;
    }

    public void setWindow(int window) {
        this.window = window;
    }
            

    @Override
    public void run(){
        try {
            sendPacks();
        } 
        catch (Exception ex) {
            System.out.println("Error");                    
        }
    }

    public synchronized void pause() {
            pause = true;
            try {
                while (pause)
                    wait();
            }
            catch(InterruptedException e) {}
    }

    public synchronized void unpause(){
        pause = false;
        notifyAll();
    }

    public synchronized void decreaseWindowSize(){
        currentWindow--;
    }

    public static byte[] filetoBytes(String source) throws FileNotFoundException, IOException{
        byte[] bytes = null;
        File file = new File(source);

        FileInputStream fis = new FileInputStream(file);

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] buf = new byte[512];
        
        for (int readNum; (readNum = fis.read(buf)) != -1;) 
            bos.write(buf, 0, readNum); 

        bytes = bos.toByteArray();
        return bytes;
    }
    
    private void generatePackets(String filename) throws IOException{

        byte[] obj = filetoBytes(filename);
        
        byte[] buff = new byte[512]; 
        int j = 0, number = 0;
        Datagram.UDPDatagram type = Datagram.UDPDatagram.DATA_TRANSFER;
        for ( int i = 0 ; i < obj.length ; i++ , j++ ){
            buff[j] = obj[i];
            if ( j == 511){
                if ( (j+1) >= obj.length ) type = datagram.Datagram.UDPDatagram.STOP_DATA_TRANSFER;
                
                Datagram aux = new Datagram(type, number++, buff);
                byte[] toSendCP = Datagram.toByteArray(aux);
                DatagramPacket pack = new DatagramPacket(toSendCP, toSendCP.length, address,3030);
                
                System.out.println(pack);
                
                toSend.add(pack);
                j = -1;
            }
        }
        if (j != 0) {
            byte[] buff2 = new byte[j];
            for( int i = 0 ; i < j ; i++ )
                buff2[i] = buff[i];
            Datagram aux = new Datagram(Datagram.UDPDatagram.STOP_DATA_TRANSFER, number, buff2);
            byte[] toSendCP = Datagram.toByteArray(aux);
            DatagramPacket pack = new DatagramPacket(toSendCP, toSendCP.length,address, 3030);

            toSend.add(pack);
        }

        String[] nomeFicheiro = filename.split("/");

        Datagram d1 = new Datagram(Datagram.UDPDatagram.FILENAME, toSend.size(),
                stringToBytes(nomeFicheiro[nomeFicheiro.length-1]));
        byte[] toSend1 = Datagram.toByteArray(d1);
        DatagramPacket pack2 = new DatagramPacket(toSend1, toSend1.length,address, 3030);

        toSend.add(0, pack2);        
    }

    public static byte[] stringToBytes(String s) {
        java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();

        try {
            java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(baos);
            oos.writeObject(s);
        }
        catch(IOException e){}

        return baos.toByteArray();
    }
    
    
    private synchronized void sendReq() {
            Datagram d = new Datagram(Datagram.UDPDatagram.CONNECT, -1 ,null);
            byte[] send = Datagram.toByteArray(d);
            DatagramPacket pack = new DatagramPacket(send, send.length,address, 3030);

            try {
                socket.send(pack);
            }
            catch(IOException e) {}
            
            Client.firstRTT = System.currentTimeMillis();
            
    }

    private synchronized void sendPacks() {
        Client.initFluxControl();
        int i=0;
        for (DatagramPacket dp : toSend){
            while ( window > currentWindow )
                pause();    
            try {
            socket.send(dp);
            }
            catch(IOException e) {}
            
            Client.getFluxControl().setTimeCountList(i, System.currentTimeMillis());
            window++;
            sent_packs++;            
            i++;
        }        
    }

    public synchronized void sendTermination() throws IOException, InterruptedException{
        Client.getRecieve().setEnded();
        Datagram d = new Datagram(Datagram.UDPDatagram.DISCONNECT,-1, null);
        byte[] send = Datagram.toByteArray(d);
        DatagramPacket pack = new DatagramPacket(send, send.length,address, 3030);

        socket.send(pack);               
    }
                    
    
}
